(function(global){
    
    var _slice = Array.prototype.slice;
    
    ujs.define('arr', 'ujs', {
        /**
         * 是否包含某元素，或一系列元素。
         * @method contains
         * @return {Boolean}
         */
        contains : function(arr, obj /*, obj2, obj3, ...*/) {
            if(ujs.Type.isUndefined(obj)){
                return false;
            }
            if(arguments.length === 2){
                var i = arr.length;
                while (i--) {
                    if (arr[i] === obj) {
                        return true;
                    }
                }
                return false;   
            } else {
                for(var j=1, jLen=arguments.length; j<jLen; j++){
                    if(!this.contains(arr, arguments[j])){
                        return false;
                    }
                }  
                return true;
            }
        },
        /**
         * 判断数组中是否至少包含一个指定的元素.
         * @method containsAtLeastOne
         * @return {Boolean}
         */
        containsAtLeastOne : function(arr, obj, obj2, obj3 /*, obj4, ...*/) {
            for(var i=1, iLen=arguments.length; i<iLen; i++){
                if(this.contains(arr, arguments[i])){
                    return true;
                }
            }  
            return false;
        },
        /**
         * 交换数组中两个元素的位置.
         * @method swapTwoItems
         * @return {Array}
         */
        swapTwoItems : function(arr, obj1, obj2){
            var pos1, pos2;
            for(var i=0, iLen=arr.length; i<iLen; i++){
                if(arr[i] === obj1) pos1 = i;
                if(arr[i] === obj2) pos2 = i;
            }
            if(pos1 > -1 && pos2 > -1){
                arr[pos1] = obj2;
                arr[pos2] = obj1;
            }
            return arr;
        },
        /**
        * 添加一个元素， 若已存在，则不添加。
        *
        * @method add
        * @param {Object|Array} obj
        * @return {Array} Array
        */
        add : function(arr, obj /*or arr*/){
            if( ujs.Type.isArray(obj) ){    //兼容add(arr, arr)
                for(var i=0,len=obj.length; i<len; i++){
                    this.add(arr, obj[i]);
                }
            } else if(arguments.length > 2){    //兼容add(arr, obj1, obj2, ...)
                for(var j=0,jLen=arguments.length; j<jLen; j++){
                    this.add(arr, arguments[j]);
                }
            } else {
                if(!this.contains(arr, obj)){
                    arr.push(obj);
                }
            }
            return arr;
        },    
        sum : function(arr){
            if(!ujs.Type.isArray(arr)){ //兼容sum(num1, num2, num3, ...)
                arr = _slice.call(arguments,0);
            }
            for(var sum=0, i=0,len=arr.length; i<len; i++){
                sum += (parseFloat(arr[i]) || 0);
            }
            return sum;
        },
        /**
         * 在数组中的指定位置添加元素.
         * @method addAt
         * @param index {Number} 要插入的位置.
         * @param obj1, obj2, ..., objn {Mixed} 要添加的数据项.
         * @return {Array} 修改后的原数组.
         */
        addAt : function(arr, index, obj /*, obj2, obj3, ...*/){
            var args = _slice.call(arguments, 0);
            if(args.length < 4){
                arr.splice(index, 0, obj);
            } else {
                args.splice(0, 1);
                args.splice(1, 0, 0);
                [].splice.apply(arr, args);
            }
            return arr;
        },
        /**
         * 移动数组中的元素到指定的位置.
         * @method move
         * @return {Array}
         */
        move : function(arr, obj, index){                
            if(arguments.length > 3){   //兼容function(arr, obj, relObj, pos).
                var relObj = index,
                    pos = arguments[3],
                    relObjIndex = this.indexOf(arr, relObj);
                if(relObjIndex > -1){
                    this.move(arr, obj, pos < 1 ? relObjIndex : ++relObjIndex);
                } else {
                    arr.push(obj);//若未找到相关元素，则将元素追加到最后。
                }
            } else {
                var originalIndex = this.indexOf(arr, obj); 
                if(index !== originalIndex){
                    //先添加元素到新位置，再删除掉老位置的元素。
                    arr.splice(index, 0, obj);
                    if(originalIndex > -1){                
                        arr.splice(index > originalIndex ? originalIndex : ++originalIndex, 1);
                    }
                }
            }
            return arr;
        },
        /**
         * 随机获取数组中的一个元素.
         * Math.random() -> 取[0,1)随机数.
         * @method getItemRandomly
         * @return {ArrayItem}
         */
        getItemRandomly : function(arr){
            return arr[Math.floor(Math.random() * arr.length)];
        },
        /**
         * 删除参数中指定的元素，参数格式如: (arr, obj1, obj2, obj3, ... )
         * @method remove
         * @return {Array}
         */
        remove : function(arr) {
            var items = arguments, 
                k = 1, 
                len = items.length, 
                item = null;
                
            for (; k < len; k++) {
                item = items[k];
                for (var i = 0, n = 0; i < arr.length; i++) {
                    if (arr[i] != item) {
                        arr[n++] = arr[i];
                    }
                }
                arr.length = n;
            }
            return arr;
        },
        /**
         * 删除指定位置的元素.
         * @method removeAt
         * @return {Array} : 被删除的元素.
         */
        removeAt : function(arr, index1, index2, index3 /*, index4, ...*/){    
            var indexArr = this.toArray(arguments);
            indexArr = this.unique(indexArr);
            indexArr = this.sortAsc(indexArr);
            indexArr = this.shrink(indexArr);            
            var indexItem;        
            while(!ujs.Type.isUndefined(indexItem = indexArr.pop())){
                arr.splice(indexItem, 1);
            }   
            return arr;
        },
        /**
         * 删除符合指定条件的数组项.
         * This function will remove any elements from the array which satisfy the conditions in the user provided function fun. 
         * If no function passed, undefined and null values are removed.
         * 本函数修改原数组.
         * @param fun {Function} : 条件函数
         */
        removeIf : function(arr, fun) {
            fun = fun || function(i) {
                return i == undefined || i == null;
            };
            for(var n=0, i=0, l=arr.length; i<l; i++){
                fun(arr[i]) ? n++ : arr[i-n] = arr[i];
            }
            arr.length = arr.length - n;
            return arr;
        },
        /**
         * 升序排列数组(适用Number与String类型的数组). 
         * @method sortAsc
         * @return {Array}
         */
        sortAsc : function(arr){
            return arr.sort(function(a,b){
                return a > b; 
            });
        },
        /**
         * 降序排列数组(适用Number与String类型的数组).
         * @method sortDesc
         * @return {Array}
         */
        sortDesc : function(arr){
            return arr.sort(function(a,b){
                return a < b;
            });
        },
        /**
         * 去除重复元素.
         * @method unique
         * @return {Array}
         */
        unique : function(arr) {    
            for (var i = 0, len = arr.length; i < len; i++) {
                for (var j = i + 1; j < len; j++) {
                    if (arr[i] === arr[j]) {
                        arr.splice(j--, 1);
                        len--;
                    }
                }
            }
            return arr;
        },
        /**
         * 取两个或多个Array的交集.
         * @method intersect
         * @return {Array}
         */
        intersect : function(arr1, arr2 /*, arr3, arr4, ...*/) {
            if(arguments.length == 2){
                var twoArr = (arr1.length > arr2.length) ? [this.unique(arr1), arr2] : [this.unique(arr2), arr1], 
                    newArr = [], 
                    longArr = twoArr[0], 
                    shortArr = twoArr[1];
                    
                for (var i=0,len=longArr.length; i<len; i++) {
                    if (this.contains(shortArr, longArr[i])) {
                        newArr.push(longArr[i]);
                    }
                }
                return newArr;
            } else {
                var newArr = this.intersect(arr1, arr2);
                if(!newArr.length){
                    return [];
                } else {
                    var otherArrs = _slice.call(arguments, 2);
                    otherArrs.unshift(newArr);
                    return this.intersect.apply(this, otherArrs);
                }
            }
        },
        /**
         * 获取数组第一个元素.
         * @method first
         * @return {ArrayItem}
         */
        first : function(arr){
            return arr[0];
        },
        /**
         * 获取数组的最后一个.
         * @method last
         * @return {ArrayItem}
         */
        last : function(arr) {
            return arr.length ? arr[arr.length - 1] : null;
        },
        /**
         * 获取数组中间的一个.
         * @method middle
         * @return {ArrayItem}
         */
        middle : function(arr) {
            if(arr.length > 0){
                return arr[Math.floor((arr.length-1)/2)];
            }
        },
        /**
         * 克隆数组.
         * @method clone
         * @return {Array}
         */
        clone : function(arr) {
            var newArr = [];
            for (var i = 0; i < arr.length; i++) {
                var item = arr[i]; 
                newArr[i] = item && item.clone ? item.clone() : item;
            }
            return newArr;
        },
        /**
         * 去除数组中的冗余空元素.
         * @method shrink
         * @return {Array}
         */
        shrink : function(arr){
            for(var i = 0, len = arr.length; i < len; i++){
                var item = arr[i];
                if(item === '' || item === null || item === undefined || (typeof item == 'number' && isNaN(item))){
                    arr.splice(i--,1);
                    len--;           
                }
            }
            return arr;
        },
        /**
         * 将二维数组转化成一维数组.
         * 如: [[1,2,3],[4,5,6,[7,8]]].linear()   =>   [1,2,3,4,5,6,[7,8]]
         * @method linear
         * @return {Array}
         */
        linear : function(d2Arr){
            return [].concat.apply([], d2Arr);
        },
        /**
         * 判断数组中是否至少有一个元素满足条件.
         * fun* ( Object, Number, Array ) : Boolean  --- callback, 
         * [ctx]  --- Object 
         * @method some
         * @return {Boolean}
         *
         * @example
         *      function isBigEnough(element, index, array) {
         *          return (element >= 10);
         *      }
         *      var passed = [2, 5, 8, 1, 4].some(isBigEnough);
         *      // passed is false
         *      var passed = [12, 5, 8, 1, 44].some(isBigEnough);
         *      // passed is true
         */
        some : function(arr, fun, ctx){
            for( var i = 0, len = arr.length; i < len; i++){
                if( fun.call( ctx || arr, arr[i], i, arr ) ){
                    return true;
                }
            }
            return false;
        },
        /**
         * 判断数组中是否所有元素均满足条件.
         * fun* ( Object, Number, Array ) : Boolean  --- callback, 
         * [ctx]  --- Object
         * @method every
         * @return {Boolean} 
         */
        every : function(arr, fun, ctx){
            for( var i = 0, len = arr.length; i < len; i++){
                if( !fun.call( ctx || arr, arr[i], i, arr ) ){
                    return false;
                }
            }
            return true;
        },
        /**
         * Creates a new array with all elements that meet the specified criteria.
         * fun* ( Object, Number, Array ) : Boolean  --- callback, 
         * [ctx]  --- Object
         * @method filter
         * @return {Array} 
         */
        filter : function(arr, fun, ctx){
            var newArr = [];
            for( var i = 0, len = arr.length; i < len; i++){
                if( fun.call( ctx || arr, arr[i], i, arr ) ){
                    newArr.push(arr[i]);
                }
            }
            return newArr;
        },    
        /**
         * 查找一个符合条件的元素.
         */
        filterOne : function(arr, fun, ctx){        
            for( var i = 0, len = arr.length; i < len; i++){
                if( fun.call( ctx || arr, arr[i], i, arr ) ){
                    return arr[i];
                }
            }
        },    
        /**
         * Executes the specified function once for each element in an array.
         * fun* ( Object, Number, Array ), 
         * [ctx]  --- Object
         * @method forEach
         * @return {Array} 
         */        
        forEach : function(arr, fun, ctx){
            for( var i = 0, len = arr.length; i < len; i++){
                if(fun.call( ctx || arr, arr[i], i, arr ) === false){
                    break;
                }
            }
            return arr;
        },
        /**
         * Returns the first index number at which the specified element can be found in the array. 
         * Returns -1 if the element is not present. 
         * @method indexOf
         * @return {Number}
         */
        indexOf : function(arr, obj, fromIndex ){
            var objIndex = -1;
            for( var i = ( fromIndex || 0 ), len = arr.length; i < len; i++){
                if( arr[i] === obj ){
                    objIndex = i;
                    break;
                }
            }
            return objIndex;
        },
        /**
         * Searches an array backwards starting from fromIndex and returns the last index number at which the specified element can be found in the array. 
         * Returns -1 if the element is not present. 
         * @method lastIndexOf
         * @return {Number}
         */
        lastIndexOf : function(arr, obj, fromIndex ){
            var objIndex = -1;
            for( var i = ( fromIndex || arr.length - 1 ); i > -1; i--){
                if( arr[i] === obj ){
                    objIndex = i;
                    break;
                }
            }
            return objIndex;
        },    
        /**
         * Creates a new array with the results of calling a provided function on every element in this array.
         * fun* ( Object, Number, Array ), 
         * [ctx]  --- Object 
         * @method map
         * @return {Array}
         */
        map : function(arr, fun, ctx){
            var newArr = [];
            for( var i = 0, len = arr.length; i < len; i++){
                newArr.push( fun.call( ctx || arr, arr[i], i, arr ) );
            }
            return newArr;
        },
        /**
         * 将数组内的元素次序打乱(洗牌).
         * @method shuffle
         * @return {Array}
         */
        shuffle : function(arr){
            arr.sort(function(){return Math.random() - 0.5;});
            return arr;
        },       
        /**
         * 清空数组.
         * @method clear
         * @return {Array}
         */
        clear : function(arr){
            arr.length = 0;
            return arr;
        },   
        /**
         * 获取数组中最大的数组项.
         * @method getMaxItem
         * @return {ArrayItem}
         */
        getMaxItem : function(arr){
            return Math.max.apply(Math, arr);
        },       
        /**
         * 获取数组中最小的数组项.
         * @method getMinItem
         * @return {ArrayItem}
         */
        getMinItem : function(arr){
            return Math.min.apply(Math, arr);
        },
        /**
         * Pad an array to a given size with a given value.
         * This function will return a copy of the array padded to length size with initial value.
         *  
         * If size is less than or equal to the length of the array a copy of the array is returned.
         * If size is negative the array is padded from the left.
         * If positive it is padded from the right.
         * 
         * @param size {Number} 数组容量.
         * @param val {Mixed} 数组填充值.
         * @method pad
         * @return {Array} 新数组实例.
         */
        pad : function(arr, size, val) {
            var count = Math.abs(size) - arr.length,
                newArr = [].concat(arr);
            if (count <= 0){
                return newArr;
            }
            for(var i=0; i<count; i++){
                size < 0 ? newArr.unshift(val) : newArr.push(val);
            }
            return newArr;
        },
        /**
         * 获取当前数组针对指定数组的差集.
         * @method subtract.
         * @return {Array}
         */
        subtract : function(arr1, arr2){
            var result = [];
            for(var i=0,len=arr1.length; i<len; i++){
                if(!arr2.contains(arr1[i])){
                    result.push(arr1[i]);
                }
            } 
            return result;
        },
        /**
         * The difference is computed as the elements which are in the calling array but not in the arrays passed as arguments.
         * Duplicates are removed from the result.
         * @method diff
         * @param arr0 - arrN {Array} ([ Array a0 ... an ]) 
         * @return {Array} A new array with those elements which are not in arrays a0 trough an.
         */
        diff : function(arr) {
            var diffArrTmp = arrN = null;
            var n = 1;
            while(n < arguments.length) {
                diffArrTmp = []; //数组差集临时存储.
                arrN = arguments[n];
                for(var diff=true, i=0,l=arr.length; i<l; i++) {
                    for(var j=0,l2 = arrN.length; j<l2; j++) {
                        if (arr[i] === arrN[j]) {
                            diff = false;
                            break;
                        }
                    }
                    diff ? diffArrTmp.push(arr[i]) : diff = true;
                }
                arr = diffArrTmp;
                n++;
            }
            return this.unique(diffArrTmp);
        },   
        /**
         * Check whether two arrays are disjoint
         * 
         * This functions checks whether two arrays are disjoint.
         * If no element is in more than one array then the arrays are considered to be disjoint.
         * 
         * @method disjoint
         * @param {Array} 
         * @return {Boolean}
         */
        disjoint : function() {
            var args = _slice.call(arguments, 0);            
            if (args.length < 2){
                return true;
            }     
            for(var i=0; i<args.length; i++){
                for(var j=i+1; j<args.length; j++){
                    if(this.intersect(args[i], args[j]).length) return false;
                }
            }
            return true;
        },
        /**
         * 重写toString方法，去掉‘逗号’字符串连接符。
         * 默认toString方法将数组中的所有项转化成字符串，而后以‘逗号’分隔连接。
         * 大多数时，我们不需要这个‘逗号’连接符。
         * @method toString
         * @param sep {String} 字符串连接符，默认空字符串。
         * @return {String}
         */
        toString : function(arr, sep){
            return arr.join(sep || '');
        },    
        /**
         * 合并多个数组为一个数组.
         * @static
         * @method merge
         * @return {Array}
         */
        merge : function(){
            var arr = [], _push = Array.prototype.push;
            for(var i=0; i<arguments.length; i++){
                _push.apply(arr, arguments[i]);    
            }
            return arr; 
        },
        /**
         * 判断指定的参数是否是一个数组.
         * @static
         * @method isArray
         * @return {Boolean}
         */
        isArray : function(obj){
            return obj instanceof Array;
        },
        /**
         * 将类数组对象转化为数组.
         * @param {Object} list
         * @static
         * @method toArray
         * @return {Array}
         */
        toArray : function(list){
            return _slice.call(list || [], 0);
        },                      
        /**
         * 获取数组.
         * @static 
         * @param {Array|Mixed} arr
         * @param {Array}
         */
        insure : function(arr){
            if(Type.isUndefined(arr)){
                return [];
            } else {
                if(!Type.isArray(arr)){
                    arr = [arr];
                }
                return arr;
            }
        }
    });
        
    ujs.alias(ujs.arr, ujs.arr.clear, 'empty');
    ujs.alias(ujs.arr, ujs.arr.forEach, 'each');
    ujs.alias(ujs.arr, ujs.arr.filter, 'find');
    ujs.alias(ujs.arr, ujs.arr.filterOne, 'findOne');
    ujs.alias(ujs.arr, ujs.arr.add, 'append');
    ujs.alias(ujs.arr, ujs.arr.getItemRandomly, 'random');
    
})(window);